package cn.bigfire.wzdj.net;

import cn.bigfire.wzdj.action.WZDJCaller;
import cn.bigfire.wzdj.frame.WZDJMainFrame;
import cn.bigfire.wzdj.pojo.bo.WZDJHeader;
import cn.bigfire.wzdj.pojo.bo.WZDJPack;
import cn.bigfire.wzdj.pojo.srcVo.Wzdj;
import cn.bigfire.wzdj.pojo.vo.WZDJLoginInfo;
import cn.bigfire.wzdj.pojo.vo.WZDJServerLogin;
import cn.bigfire.wzdj.util.ByteUtil;
import cn.bigfire.wzdj.util.PackUtil;
import cn.bigfire.wzdj.util.Stores;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Slf4j
@ChannelHandler.Sharable
public class WZDJWSClientHandler extends SimpleChannelInboundHandler<WZDJPack> {

    WZDJCaller wzdjCaller = new WZDJCaller();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WZDJPack wzdjPack) throws Exception {
        if (wzdjPack != null) {
            wzdjCaller.call(ctx.channel(), wzdjPack);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("连接:" + ctx.channel().remoteAddress().toString());
        if (ctx.channel().equals(Stores.getInstance().getHomeChannel())) {
            new Thread(() -> {
                try {
                    for (int i = 0; i < 5; i++) {//尝试5次
                        if (!Stores.getInstance().isLogin()){
                            log.info("第{}次尝试登录大厅",(i+1));
                            homeLogin();
                            ThreadUtil.sleep(3000);
                        } else {
                            break;
                        }
                    }
                } catch (Exception e) {
                    String throwableStr = throwableStr(e);
                    log.error(throwableStr);
                    WZDJMainFrame.consoleTextArea.append(throwableStr);
                } catch (Throwable throwable) {
                    String throwableStr = throwableStr(throwable);
                    log.error(throwableStr);
                    WZDJMainFrame.consoleTextArea.append(throwableStr);
                }
            }).start();
        } else if (ctx.channel().equals(Stores.getInstance().getFightChannel())) {
            new Thread(() -> {
                try {
                    for (int i = 0; i < 5; i++) {//尝试5次
                        if (!Stores.getInstance().getIsFight().get()){
                            log.info("第{}次尝试登录战斗服",(i+1));
                            fightLogin();
                            ThreadUtil.sleep(5000);
                        } else {
                            break;
                        }
                    }
                } catch (Exception e) {
                    String throwableStr = throwableStr(e);
                    log.error(throwableStr);
                    WZDJMainFrame.consoleTextArea.append(throwableStr);
                } catch (Throwable throwable) {
                    String throwableStr = throwableStr(throwable);
                    log.error(throwableStr);
                    WZDJMainFrame.consoleTextArea.append(throwableStr);
                }

            }).start();
        } else {
            log.error("未知连接:" + ctx.channel().remoteAddress().toString());
            new Thread(() -> {
                try {
                    for (int i = 0; i < 5; i++) {//尝试5次
                        if (!Stores.getInstance().isLogin()){
                            log.info("第{}次尝试登录大厅",(i+1));
                            homeLogin();
                            ThreadUtil.sleep(3000);
                        } else {
                            break;
                        }
                    }
                } catch (Exception e) {
                    String throwableStr = throwableStr(e);
                    log.error(throwableStr);
                    WZDJMainFrame.consoleTextArea.append(throwableStr);
                } catch (Throwable throwable) {
                    String throwableStr = throwableStr(throwable);
                    log.error(throwableStr);
                    WZDJMainFrame.consoleTextArea.append(throwableStr);
                }
            }).start();
        }
    }

    public static void homeLogin(){
        String errStr = "";
        try {
            WZDJServerLogin wzdjServerLogin = new WZDJServerLogin();
            WZDJLoginInfo wzdjInfo = new WZDJLoginInfo();
            wzdjInfo.getExtraParams().setKey("wxOpenId");
            wzdjInfo.getExtraParams().setVal(Stores.getInstance().getUserInfo().getUuid());
            wzdjInfo.setInternalToken(Stores.getInstance().getUserInfo().getToken());
            wzdjServerLogin.setInfo(wzdjInfo);
            WZDJHeader wzdjHeader = WZDJHeader.ofById(655363);
            WZDJPack<WZDJServerLogin> wzdjPack = new WZDJPack<>(wzdjHeader, wzdjServerLogin);
            ByteBuf buffer = Unpooled.buffer();
            byte[] bytes = wzdjPack.getBytes();
            log.info("登录数据包大小:" + ByteUtil.getSize(bytes.length));
            buffer.writeBytes(bytes);
            BinaryWebSocketFrame binaryWebSocketFrame = new BinaryWebSocketFrame(buffer);
            Stores.getInstance().getHomeChannel().writeAndFlush(binaryWebSocketFrame);
        } catch (Exception e) {
            String throwableStr = throwableStr(e);
            errStr += throwableStr;
            errStr += e.getLocalizedMessage() + "\n";
            log.error(errStr);
            WZDJMainFrame.consoleTextArea.append(errStr);
        } catch (Throwable throwable) {
            String throwableStr = throwableStr(throwable);
            errStr += throwableStr;
            errStr += throwable.getLocalizedMessage() + "\n";
            log.error(errStr);
            WZDJMainFrame.consoleTextArea.append(errStr);
        }
    }

    public static String throwableStr(Throwable throwable) {
        StringBuilder sb = new StringBuilder();
        StackTraceElement[] stackTrace = throwable.getStackTrace();
        for (StackTraceElement stackTraceElement : stackTrace) {
            final String className = stackTraceElement.getClassName();
            final String methodName = stackTraceElement.getMethodName();
            final String fileName = stackTraceElement.getFileName();
            final Integer lineNumber = stackTraceElement.getLineNumber();
            String format = String.format("%s.%s(%s:%s)%n", className, methodName, fileName, lineNumber);
            sb.append(format);
        }
        return sb.toString();
    }

    public static void fightLogin(){
        try {
            Wzdj.RpcClientFightMatchSuccess rpcClientFightMatchSuccess = Stores.getInstance().getRpcClientFightMatchSuccess();
            String ip = rpcClientFightMatchSuccess.getServer().getIp();
            int port = rpcClientFightMatchSuccess.getServer().getPort() != 0 ? rpcClientFightMatchSuccess.getServer().getPort() : 0;
            String token = rpcClientFightMatchSuccess.getServer().getToken();
            System.out.printf("登录战斗服 ip:%s,port:%s,token:%s%n", ip, port, token);
            //战斗服 第一个接口 登录
            Wzdj.RpcServerFightLogin rpcServerFightLogin1 = new Wzdj.RpcServerFightLogin();
            rpcServerFightLogin1.setToken(rpcClientFightMatchSuccess.getServer().getToken());
            rpcServerFightLogin1.setUid(Stores.getInstance().getBasicInfo().getUid());// 获取第一位玩家信息sa
            PackUtil.send(Stores.getInstance().getFightChannel(), rpcServerFightLogin1);

            //存储对方的uid 用于局内聊天
            List<Wzdj.MatchPlayerData> players = rpcClientFightMatchSuccess.getPlayers();
            for (Wzdj.MatchPlayerData player : players) {
                Integer uid = player.getUserinfo().getUid();
                if (!Objects.equals(uid, Stores.getInstance().getBasicInfo().getUid())) {
                    Stores.getInstance().setItUid(uid);//进桌获取对方用户id，用于后续私聊使用。
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        InetSocketAddress closeAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        String remoteAddress = closeAddress.toString();

        if (Stores.getInstance().getHomeChannel() != null) {
            InetSocketAddress homeAddress = (InetSocketAddress) Stores.getInstance().getHomeChannel().remoteAddress();
            if (closeAddress.getPort() == homeAddress.getPort()) {//
                log.error("断开 大厅:" + remoteAddress);
                WZDJMainFrame.consoleTextArea.append(DateUtil.formatDateTime(new Date()) + "大厅断开连接,请尝试重新连接服务器\n");
                Stores.getInstance().setHomeChannel(null);
                Stores.getInstance().setUserInfo(null);
                Stores.getInstance().setLogin(false);
            }
        }
        if (Stores.getInstance().getFightChannel() != null) {
            InetSocketAddress fightAddress = (InetSocketAddress) Stores.getInstance().getFightChannel().remoteAddress();
            if (closeAddress.getPort() == fightAddress.getPort()) {
                log.error("断开 战斗服:" + remoteAddress);
                Stores.getInstance().getIsFight().set(false);
                Stores.getInstance().setBattleType(0);
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.info("异常:" + cause.toString());
        cause.printStackTrace();
    }

}
